#include "../Headers/tOpSysQ.hpp"

#include <Windows.h>
#include <Psapi.h>
#include <iostream>
#include <SetupAPI.h>

using namespace std;


void TOpSysQ::getMemoryUsage() {
#define BYTE_TO_MB 1048576
	//	MEMORYSTATUSEX statex;
	//	statex.dwLength = sizeof(statex);
	//	GlobalMemoryStatusEx(&statex);
	//	_tprintf(TEXT("There are %*I64d total Mbytes of physical memory.\n"), 7, statex.ullTotalPhys / BYTE_TO_MB);
	//	_tprintf(TEXT("There is  %*ld percent of memory in use.\n"), 7, statex.dwMemoryLoad);
	//	_tprintf(TEXT("There are %*I64d free Mbytes of physical memory.\n"), 7, statex.ullAvailPhys / BYTE_TO_MB);
	PROCESS_MEMORY_COUNTERS pmc;
	GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
	SIZE_T virtualMemUsedByMe = pmc.WorkingSetSize;
	//_tprintf(TEXT("There are %*I64d total Mbytes of physical memory used by current process.\n"), 7, virtualMemUsedByMe / BYTE_TO_MB);

	//_tprintf(TEXT("There are %*I64d total Mbytes of physical memory used by current process.\n"), 7, virtualMemUsedByMe / BYTE_TO_MB);
}

int TOpSysQ::getMemoryCapacityMB() {
	MEMORYSTATUSEX statex;

	statex.dwLength = sizeof(statex); // I misunderstand that

	GlobalMemoryStatusEx(&statex);
	return (int)(statex.ullTotalPhys / 1024 * 1024);
}


bool TOpSysQ::checkDriver() {
	SC_HANDLE h_SCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);

	ENUM_SERVICE_STATUS struct_ServiceStatus;
	ENUM_SERVICE_STATUS* lpServiceStatus = nullptr;
	BOOL b_RetVal = FALSE;
	DWORD dw_BytesNeeded;
	DWORD dw_ServiceCount;
	DWORD dw_ResumeHandle = 0;
	DWORD dw_ServiceType;
	DWORD dw_ServiceState;

	//We are interested only in drivers
	dw_ServiceType = SERVICE_DRIVER;
	// interested to know about drivers in all states
	dw_ServiceState = SERVICE_STATE_ALL;
	//Call EnumServicesStatus using the handle returned by OpenSCManager
	b_RetVal = ::EnumServicesStatus(h_SCM,
		dw_ServiceType,
		dw_ServiceState,
		&struct_ServiceStatus,
		sizeof(struct_ServiceStatus),
		&dw_BytesNeeded,
		&dw_ServiceCount,
		&dw_ResumeHandle);
	DWORD dw_Error = GetLastError();
	if ((b_RetVal == FALSE) || dw_Error == ERROR_MORE_DATA)
	{
		DWORD dw_Bytes = dw_BytesNeeded + sizeof(ENUM_SERVICE_STATUS);
		lpServiceStatus = new ENUM_SERVICE_STATUS[dw_Bytes];
		EnumServicesStatus(h_SCM,
			dw_ServiceType,
			dw_ServiceState,
			lpServiceStatus,
			dw_Bytes,
			&dw_BytesNeeded,
			&dw_ServiceCount,
			&dw_ResumeHandle);
	}

	SC_HANDLE h_ServiceHandle = NULL;
	//for (unsigned int i = 0; i < dw_ServiceCount; i++)
	//{
	//	//h_ServiceHandle = NULL;
	//	//h_ServiceHandle = OpenService(h_SCM, lpServiceStatus[i].lpServiceName, SERVICE_ALL_ACCESS);
	//	cout << string(lpServiceStatus[i].lpServiceName.c) << endl;
	//}
	return false;
}

void TOpSysQ::waitForEnter() {
	cout << "Enter to continue...";
	getchar();
	cout << " OK" << endl;
}

bool TOpSysQ::isKeyDown(char keyIn) {
	// always capped
	if (keyIn >= 'a' && keyIn <= 'z') {
		keyIn += ('A' - 'a');
	}
	SHORT state = GetKeyState(keyIn);
	return state & 0x8000;
}

bool TOpSysQ::isAnyCharKeyDown() {
	// always caped
	for (char c = 'A'; c <= 'Z'; c++) {
		if (isKeyDown(c)) {
			cout << "Key " << c << " pressed" << endl;
			return true;
		}
	}
	return false;
}

int TOpSysQ::checkUSBDevices() {
	// https://docs.microsoft.com/en-us/windows/win32/api/setupapi/nf-setupapi-setupdigetclassdevsw

	HDEVINFO dev_info;
	SP_DEVINFO_DATA dev_info_data;
	int dev_index = 0;
	int ret = FALSE;

	dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
	dev_info = SetupDiGetClassDevs(NULL, L"USB", NULL,
		DIGCF_ALLCLASSES | DIGCF_PRESENT);

	//SetEnvironmentVariable("LIBUSB_NEEDS_REBOOT", "1");

	if (dev_info == INVALID_HANDLE_VALUE)
	{
		//usb_error("usb_install_needs_restart_np(): getting "
		//	"device info set failed");
		return -1;
	}

	while (SetupDiEnumDeviceInfo(dev_info, dev_index, &dev_info_data))
	{
		DWORD regDataType;
		DWORD reqSize = 0;

		// find the size required to hold the device info
		BYTE* hardwareId = new BYTE[(reqSize > 1) ? reqSize : 1];
		SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_HARDWAREID, nullptr, nullptr, 0, &reqSize);

		dev_index++;
	}

	SetupDiDestroyDeviceInfoList(dev_info);

	return ret;
}

std::string TOpSysQ::getPlatformName() {
	string ret;
#ifdef NDEBUG
	ret += "Release_";
#else
	ret += "Debug_";
#endif
#ifdef _CONSOLE
	ret += "Console_";
#else
	ret += "Lib_";
#endif
	return ret;
}
